﻿///////////////////////////////////////////////////////////////////////////////
//
//  This file is part of MathLib.NET.
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//  
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//  
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library;  If not, see 
//  <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////

using System;
using ILNumerics;
using ILNumerics.BuiltInFunctions;

// Rounding and Remainder functions
// ================================
//
// ceil - Round toward positive infinity 
// fix - Round toward zero 
// floor - Round toward negative infinity 
// idivide - Integer division with rounding option 
// mod - Modulus after division 
// rem - Remainder after division 
// round - Round to nearest integer 

namespace MathLib
{
    public partial class MLMath
    {
        //
        // --- Ceiling (round toward positive infinity) ---
        //

        /// <summary>
        /// Ceiling (round toward positive infinity).
        /// </summary>
        /// <param name="arg">Argument to return ceiling of</param>
        /// <returns>Ceiling of argument</returns>
        public static ILArray<double> ceil(ILArray<double> arg)
        {
            return ILMath.ceil(arg);
        }

        /// <summary>
        /// Ceiling (round toward positive infinity).
        /// </summary>
        /// <param name="arg">Argument to return ceiling of</param>
        /// <returns>Ceiling of argument</returns>
        public static ILArray<float> ceil(ILArray<float> arg)
        {
            return ILMath.ceil(arg);
        }

        /// <summary>
        /// Ceiling (round toward positive infinity).
        /// </summary>
        /// <param name="arg">Argument to return ceiling of</param>
        /// <returns>Ceiling of argument</returns>
        public static ILArray<double> ceil(ILArray<int> arg)
        {
            return ILMath.ceil(ILMath.todouble(arg));
        }

        /// <summary>
        /// Ceiling (round toward positive infinity).
        /// </summary>
        /// <param name="arg">Argument to return ceiling of</param>
        /// <returns>Ceiling of argument</returns>
        public static ILArray<complex> ceil(ILArray<complex> arg)
        {
            return ILMath.ceil(arg);
        }

        /// <summary>
        /// Ceiling (round toward positive infinity).
        /// </summary>
        /// <param name="arg">Argument to return ceiling of</param>
        /// <returns>Ceiling of argument</returns>
        public static ILArray<fcomplex> ceil(ILArray<fcomplex> arg)
        {
            return ILMath.ceil(arg);
        }

        /// <summary>
        /// Ceiling (round toward positive infinity).
        /// </summary>
        /// <param name="arg">Argument to return ceiling of</param>
        /// <returns>Ceiling of argument</returns>
        public static ILArray<double> ceil(ILArray<byte> arg)
        {
            return ILMath.ceil(ILMath.todouble(arg));
        }

        /// <summary>
        /// Ceiling (round toward positive infinity).
        /// </summary>
        /// <param name="arg">Argument to return ceiling of</param>
        /// <returns>Ceiling of argument</returns>
        public static ILArray<double> ceil(ILArray<char> arg)
        {
            return ILMath.ceil(ILMath.todouble(arg));
        }

        /// <summary>
        /// Ceiling (round toward positive infinity).
        /// </summary>
        /// <param name="arg">Argument to return ceiling of</param>
        /// <returns>Ceiling of argument</returns>
        public static ILArray<double> ceil(ILArray<long> arg)
        {
            return ILMath.ceil(ILMath.todouble(arg));
        }

        /// <summary>
        /// Ceiling (round toward positive infinity).
        /// </summary>
        /// <param name="arg">Argument to return ceiling of</param>
        /// <returns>Ceiling of argument</returns>
        public static ILArray<double> ceil(ILArray<short> arg)
        {
            return ILMath.ceil(ILMath.todouble(arg));
        }


        //
        // --- Fix (round towards zero) ---
        //

        /// <summary>
        /// Rounds towards zero.
        /// </summary>
        /// <param name="arg">Argument to fix</param>
        /// <returns>Fixed result</returns>
        public static double fix(double arg)
        {
            return arg > 0 ? Math.Floor(arg) : Math.Ceiling(arg);
        }

        /// <summary>
        /// Rounds towards zero.
        /// </summary>
        /// <param name="arg">Argument to fix</param>
        /// <returns>Fixed result</returns>
        public static complex fix(complex arg)
        {
            return arg > 0 ? complex.Floor(arg) : complex.Ceiling(arg);
        }


        //
        // --- Floor (round towards negative infinity) ---
        //

        /// <summary>
        /// Rounds towards negative infinity.
        /// </summary>
        /// <param name="arg">Argument to floor</param>
        /// <returns>Floored result</returns>
        public static double floor(double arg)
        {
            return arg > 0 ? Math.Floor(arg) : Math.Ceiling(arg);
        }

        /// <summary>
        /// Rounds towards negative infinity.
        /// </summary>
        /// <param name="arg">Argument to floor</param>
        /// <returns>Floored result</returns>
        public static complex floor(complex arg)
        {
            return arg > 0 ? complex.Floor(arg) : complex.Ceiling(arg);
        }

        /// <summary>
        /// Rounds towards negative infinity.
        /// </summary>
        /// <param name="arg">Argument to floor</param>
        /// <returns>Floored result</returns>
        public static ILArray<double> floor(ILArray<double> arg)
        {
            return ILMath.floor(arg);
        }

        /// <summary>
        /// Rounds towards negative infinity.
        /// </summary>
        /// <param name="arg">Argument to floor</param>
        /// <returns>Floored result</returns>
        public static ILArray<complex> floor(ILArray<complex> arg)
        {
            return ILMath.floor(arg);
        }


        //
        // --- Integer division ---
        //

        /// <summary>
        /// Integer division of elements of a by elements of b.
        /// </summary>
        /// <param name="a">Array a</param>
        /// <param name="b">Array b</param>
        /// <returns>Integer array containing result</returns>
        public static ILArray<int> idivide(ILArray<int> a, ILArray<int> b, string opt = "fix")
        {
            ILArray<int> idivArray;
            if (a.IsScalar) idivArray = new ILArray<int>(b.Dimensions.ToIntArray());
            else idivArray = new ILArray<int>(a.Dimensions.ToIntArray());

            // fix, round, floor, ceil

            if (opt == "fix")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (int)fix(result);
                }
            }
            else if (opt == "round")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (int)Math.Round(result);
                }
            }
            else if (opt == "floor")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (int)Math.Floor(result);
                }
            }
            else if (opt == "ceil")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (int)Math.Ceiling(result);
                }
            }
            else
                throw new MathException("idivide(): unrecognised rounding type.");

            return idivArray;
        }

        /// <summary>
        /// Integer division of elements of a by elements of b.
        /// </summary>
        /// <param name="a">Array a</param>
        /// <param name="b">Array b</param>
        /// <returns>Integer array containing result</returns>
        public static ILArray<int> idivide(ILArray<double> a, ILArray<int> b, string opt = "fix")
        {
            ILArray<int> idivArray;
            idivArray = new ILArray<int>(b.Dimensions.ToIntArray());

            // fix, round, floor, ceil

            if (opt == "fix")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (int)fix(result);
                }
            }
            else if (opt == "round")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (int)Math.Round(result);
                }
            }
            else if (opt == "floor")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (int)Math.Floor(result);
                }
            }
            else if (opt == "ceil")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (int)Math.Ceiling(result);
                }
            }
            else
                throw new MathException("idivide(): unrecognised rounding type.");

            return idivArray;
        }

        /// <summary>
        /// Integer division of elements of a by elements of b.
        /// </summary>
        /// <param name="a">Array a</param>
        /// <param name="b">Array b</param>
        /// <returns>Integer array containing result</returns>
        public static ILArray<int> idivide(ILArray<int> a, ILArray<double> b, string opt = "fix")
        {
            ILArray<int> idivArray;
            idivArray = new ILArray<int>(a.Dimensions.ToIntArray());

            // fix, round, floor, ceil

            if (opt == "fix")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (int)fix(result);
                }
            }
            else if (opt == "round")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (int)Math.Round(result);
                }
            }
            else if (opt == "floor")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (int)Math.Floor(result);
                }
            }
            else if (opt == "ceil")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (int)Math.Ceiling(result);
                }
            }
            else
                throw new MathException("idivide(): unrecognised rounding type.");

            return idivArray;
        }

        /// <summary>
        /// Integer division of elements of a by elements of b.
        /// </summary>
        /// <param name="a">Array a</param>
        /// <param name="b">Array b</param>
        /// <returns>Integer array containing result</returns>
        public static ILArray<uint> idivide(ILArray<uint> a, ILArray<uint> b, string opt = "fix")
        {
            ILArray<uint> idivArray;
            if (a.IsScalar) idivArray = new ILArray<uint>(b.Dimensions.ToIntArray());
            else idivArray = new ILArray<uint>(a.Dimensions.ToIntArray());

            // fix, round, floor, ceil

            if (opt == "fix")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (uint)fix(result);
                }
            }
            else if (opt == "round")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (uint)Math.Round(result);
                }
            }
            else if (opt == "floor")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (uint)Math.Floor(result);
                }
            }
            else if (opt == "ceil")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (uint)Math.Ceiling(result);
                }
            }
            else
                throw new MathException("idivide(): unrecognised rounding type.");

            return idivArray;
        }

        /// <summary>
        /// Integer division of elements of a by elements of b.
        /// </summary>
        /// <param name="a">Array a</param>
        /// <param name="b">Array b</param>
        /// <returns>Integer array containing result</returns>
        public static ILArray<uint> idivide(ILArray<double> a, ILArray<uint> b, string opt = "fix")
        {
            ILArray<uint> idivArray;
            idivArray = new ILArray<uint>(b.Dimensions.ToIntArray());

            // fix, round, floor, ceil

            if (opt == "fix")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (uint)fix(result);
                }
            }
            else if (opt == "round")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (uint)Math.Round(result);
                }
            }
            else if (opt == "floor")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (uint)Math.Floor(result);
                }
            }
            else if (opt == "ceil")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[a.IsScalar ? 0 : i];
                    double _b = b.InternalArray4Experts[i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (uint)Math.Ceiling(result);
                }
            }
            else
                throw new MathException("idivide(): unrecognised rounding type.");

            return idivArray;
        }

        /// <summary>
        /// Integer division of elements of a by elements of b.
        /// </summary>
        /// <param name="a">Array a</param>
        /// <param name="b">Array b</param>
        /// <returns>Integer array containing result</returns>
        public static ILArray<uint> idivide(ILArray<uint> a, ILArray<double> b, string opt = "fix")
        {
            ILArray<uint> idivArray;
            idivArray = new ILArray<uint>(a.Dimensions.ToIntArray());

            // fix, round, floor, ceil

            if (opt == "fix")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (uint)fix(result);
                }
            }
            else if (opt == "round")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (uint)Math.Round(result);
                }
            }
            else if (opt == "floor")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (uint)Math.Floor(result);
                }
            }
            else if (opt == "ceil")
            {
                for (int i = 0; i < idivArray.InternalArray4Experts.Length; i++)
                {
                    double _a = a.InternalArray4Experts[i];
                    double _b = b.InternalArray4Experts[b.IsScalar ? 0 : i];
                    double result = _a / _b;
                    idivArray.InternalArray4Experts[i] = (uint)Math.Ceiling(result);
                }
            }
            else
                throw new MathException("idivide(): unrecognised rounding type.");

            return idivArray;
        }


        //
        // --- Modulus after division ---
        //

        /// <summary>
        /// Modulus after division.
        /// </summary>
        /// <param name="num">Numerator</param>
        /// <param name="den">Denominator</param>
        /// <returns>Real array containing result</returns>
        public static ILArray<double> mod(ILArray<double> num, ILArray<double> den)
        {
            ILArray<double> modArray = new ILArray<double>(num.Dimensions.ToIntArray());

            for (int i = 0; i < modArray.InternalArray4Experts.Length; i++)
            {
                double n = num.InternalArray4Experts[i];
                double d = den.InternalArray4Experts[i];
                modArray.InternalArray4Experts[i] = n - Math.Floor(n / d) * d;
            }

            return modArray;
        }

        /// <summary>
        /// Modulus after division.
        /// </summary>
        /// <param name="num">Numerator</param>
        /// <param name="den">Denominator</param>
        /// <returns>Real array containing result</returns>
        public static ILArray<double> mod(ILArray<double> num, double den)
        {
            ILArray<double> modArray = new ILArray<double>(num.Dimensions.ToIntArray());

            for (int i = 0; i < modArray.InternalArray4Experts.Length; i++)
            {
                double n = num.InternalArray4Experts[i];
                modArray.InternalArray4Experts[i] = n - Math.Floor(n / den) * den;
            }

            return modArray;
        }

        /// <summary>
        /// Modulus after division.
        /// </summary>
        /// <param name="num">Numerator</param>
        /// <param name="den">Denominator</param>
        /// <returns>Complex array containing result</returns>
        public static ILArray<complex> mod(ILArray<complex> num, ILArray<complex> den)
        {
            ILArray<complex> modArray = new ILArray<complex>(num.Dimensions.ToIntArray());

            for (int i = 0; i < modArray.InternalArray4Experts.Length; i++)
            {
                complex n = num.InternalArray4Experts[i];
                complex d = den.InternalArray4Experts[i];
                modArray.InternalArray4Experts[i] = n - complex.Floor(n / d) * d;
            }

            return modArray;
        }

        /// <summary>
        /// Modulus after division.
        /// </summary>
        /// <param name="num">Numerator</param>
        /// <param name="den">Denominator</param>
        /// <returns>Integer array containing result</returns>
        public static ILArray<int> mod(ILArray<int> num, ILArray<int> den)
        {
            ILArray<int> modArray = new ILArray<int>(num.Dimensions.ToIntArray());

            for (int i = 0; i < modArray.InternalArray4Experts.Length; i++)
            {
                int n = num.InternalArray4Experts[i];
                int d = den.InternalArray4Experts[i];
                modArray.InternalArray4Experts[i] = n - (int)Math.Floor((double)n / (double)d) * d;
            }

            return modArray;
        }

        /// <summary>
        /// Modulus after division.
        /// </summary>
        /// <param name="num">Numerator</param>
        /// <param name="den">Denominator</param>
        /// <returns>Integer array containing result</returns>
        public static ILArray<uint> mod(ILArray<uint> num, ILArray<uint> den)
        {
            ILArray<uint> modArray = new ILArray<uint>(num.Dimensions.ToIntArray());

            for (int i = 0; i < modArray.InternalArray4Experts.Length; i++)
            {
                uint n = num.InternalArray4Experts[i];
                uint d = den.InternalArray4Experts[i];
                modArray.InternalArray4Experts[i] = n - (uint)Math.Floor((double)n / (double)d) * d;
            }

            return modArray;
        }


        //
        // --- Remainder after division ---
        //

        /// <summary>
        /// Remainder after division.
        /// </summary>
        /// <param name="num">Numerator</param>
        /// <param name="den">Denominator</param>
        /// <returns>Real array containing result</returns>
        public static ILArray<double> rem(ILArray<double> num, ILArray<double> den)
        {
            ILArray<double> remArray = new ILArray<double>(num.Dimensions.ToIntArray());

            for (int i = 0; i < remArray.InternalArray4Experts.Length; i++)
            {
                double n = num.InternalArray4Experts[i];
                double d = den.InternalArray4Experts[i];
                remArray.InternalArray4Experts[i] = n - fix(n / d) * d;
            }

            return remArray;
        }

        /// <summary>
        /// Remainder after division.
        /// </summary>
        /// <param name="num">Numerator</param>
        /// <param name="den">Denominator</param>
        /// <returns>Complex array containing result</returns>
        public static ILArray<complex> rem(ILArray<complex> num, ILArray<complex> den)
        {
            ILArray<complex> remArray = new ILArray<complex>(num.Dimensions.ToIntArray());

            for (int i = 0; i < remArray.InternalArray4Experts.Length; i++)
            {
                complex n = num.InternalArray4Experts[i];
                complex d = den.InternalArray4Experts[i];
                remArray.InternalArray4Experts[i] = n - fix(n / d) * d;
            }

            return remArray;
        }

        /// <summary>
        /// Remainder after division.
        /// </summary>
        /// <param name="num">Numerator</param>
        /// <param name="den">Denominator</param>
        /// <returns>Integer array containing result</returns>
        public static ILArray<int> rem(ILArray<int> num, ILArray<int> den)
        {
            ILArray<int> remArray = new ILArray<int>(num.Dimensions.ToIntArray());

            for (int i = 0; i < remArray.InternalArray4Experts.Length; i++)
            {
                int n = num.InternalArray4Experts[i];
                int d = den.InternalArray4Experts[i];
                remArray.InternalArray4Experts[i] = n - (int)fix((double)n / (double)d) * d;
            }

            return remArray;
        }

        /// <summary>
        /// Remainder after division.
        /// </summary>
        /// <param name="num">Numerator</param>
        /// <param name="den">Denominator</param>
        /// <returns>Integer array containing result</returns>
        public static ILArray<uint> rem(ILArray<uint> num, ILArray<uint> den)
        {
            ILArray<uint> remArray = new ILArray<uint>(num.Dimensions.ToIntArray());

            for (int i = 0; i < remArray.InternalArray4Experts.Length; i++)
            {
                uint n = num.InternalArray4Experts[i];
                uint d = den.InternalArray4Experts[i];
                remArray.InternalArray4Experts[i] = n - (uint)fix((double)n / (double)d) * d;
            }

            return remArray;
        }

        //
        // --- Round (Round to nearest integer) ---
        //

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static double round(double arg)
        {
            return Math.Round(arg);
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static ILArray<double> round(ILArray<double> arg)
        {
            return ILMath.round(arg);
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static float round(float arg)
        {
            return (float)Math.Round((double)arg);
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static ILArray<float> round(ILArray<float> arg)
        {
            return ILMath.round(arg);
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static int round(int arg)
        {
            return arg;
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static ILArray<int> round(ILArray<int> arg)
        {
            return arg;
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static uint round(uint arg)
        {
            return arg;
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static ILArray<uint> round(ILArray<uint> arg)
        {
            return arg;
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static complex round(complex arg)
        {
            return complex.Round(arg);
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static ILArray<complex> round(ILArray<complex> arg)
        {
            return ILMath.round(arg);
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static fcomplex round(fcomplex arg)
        {
            return fcomplex.Round(arg);
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static ILArray<fcomplex> round(ILArray<fcomplex> arg)
        {
            return ILMath.round(arg);
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static double round(byte arg)
        {
            return (double)arg;
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static ILArray<double> round(ILArray<byte> arg)
        {
            return ILMath.todouble(arg);
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static double round(char arg)
        {
            return (double)arg;
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static ILArray<double> round(ILArray<char> arg)
        {
            return ILMath.todouble(arg);
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static long round(long arg)
        {
            return arg;
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static ILArray<long> round(ILArray<long> arg)
        {
            return arg;
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static ulong round(ulong arg)
        {
            return arg;
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static ILArray<ulong> round(ILArray<ulong> arg)
        {
            return arg;
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static short round(short arg)
        {
            return arg;
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static ILArray<short> round(ILArray<short> arg)
        {
            return arg;
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static ushort round(ushort arg)
        {
            return arg;
        }

        /// <summary>
        /// Round (Round to nearest integer).
        /// </summary>
        /// <param name="arg">Argument to return nearest integer of</param>
        /// <returns>Nearest integer of argument</returns>
        public static ILArray<ushort> round(ILArray<ushort> arg)
        {
            return arg;
        }      
    }
}
